package com.md.config.database;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils;
import lombok.Getter;
import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;

import java.util.List;
import java.util.function.Predicate;

/**
 * @author 刘骄阳
 * 2022-06-12 0:09
 */
public class CustomSqlInjector extends DefaultSqlInjector {

  @Override
  public List<AbstractMethod> getMethodList(final Class<?> mapperClass, final TableInfo tableInfo) {
    // 获取父类SQL注入方法列表
    List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
    // 将批量插入方法添加进去
    methodList.add(new CustomInsertBatchSomeColumn(predicate -> !predicate.isLogicDelete()));
    return methodList;
  }

  @Getter
  public static class CustomInsertBatchSomeColumn extends AbstractMethod {
    private final Predicate<TableFieldInfo> predicate;

    public CustomInsertBatchSomeColumn(final String methodName, final Predicate<TableFieldInfo> predicate) {
      super(methodName);
      this.predicate = predicate;
    }

    public CustomInsertBatchSomeColumn(final Predicate<TableFieldInfo> predicate) {
      super("insertBatchSomeColumn");
      this.predicate = predicate;
    }

    public MappedStatement injectMappedStatement(final Class<?> mapperClass,
                                                 final Class<?> modelClass,
                                                 final TableInfo tableInfo) {
      KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE;
      SqlMethod sqlMethod = SqlMethod.INSERT_ONE;

      List<TableFieldInfo> fieldList = tableInfo.getFieldList();

      // 生成insert的列
      String insertSqlColumn = tableInfo.getKeyInsertSqlColumn(true, false) + this.filterTableFieldInfo(fieldList, this.predicate, TableFieldInfo::getInsertSqlColumn, EMPTY);
      String columnScript = LEFT_BRACKET + insertSqlColumn.substring(0, insertSqlColumn.length() - 1) + RIGHT_BRACKET;
      String insertSqlProperty = tableInfo.getKeyInsertSqlProperty(true, ENTITY_DOT, false) + this.filterTableFieldInfo(fieldList, this.predicate, (i) -> i.getInsertSqlProperty(ENTITY_DOT), EMPTY);
      insertSqlProperty = LEFT_BRACKET + insertSqlProperty.substring(0, insertSqlProperty.length() - 1) + RIGHT_BRACKET;
      String valuesScript = SqlScriptUtils.convertForeach(insertSqlProperty, LIST, null, ENTITY, COMMA);
      String keyProperty = null;
      String keyColumn = null;
      if (tableInfo.havePK()) {
        if (tableInfo.getIdType() == IdType.AUTO) {
          /* 自增主键 */
          keyGenerator = Jdbc3KeyGenerator.INSTANCE;
          keyProperty = tableInfo.getKeyProperty();
          keyColumn = tableInfo.getKeyColumn();
        } else if (null != tableInfo.getKeySequence()) {
          keyGenerator = TableInfoHelper.genKeyGenerator(methodName, tableInfo, this.builderAssistant);
          keyProperty = tableInfo.getKeyProperty();
          keyColumn = tableInfo.getKeyColumn();
        }
      }

      String sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(), columnScript, valuesScript);
      SqlSource sqlSource = this.languageDriver.createSqlSource(this.configuration, sql, modelClass);
      return this.addInsertMappedStatement(mapperClass, modelClass, methodName, sqlSource, keyGenerator, keyProperty,
        keyColumn);
    }
  }
}
